﻿using System;
using System.Data;
using System.Collections;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Security;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.Utilities;

namespace Version3.SharePoint
{

    //this is the control suite that provides for the
    //enttity picker implementation to lookup   values 
    //from a list and to populate the select box
    //values on the main form

    #region EntityEditorWithPicker
    [CLSCompliant(false)]
    [Guid("BC25847B-3479-451a-B04F-0945A5861082")]
    public class ContentLookupFieldEntityEditor : Microsoft.SharePoint.WebControls.EntityEditorWithPicker
    {
        private string _WebURL = string.Empty;
        private string _ListName = string.Empty;
        private string _FieldOne = string.Empty;
        private string _FieldTwo = string.Empty;
        private string _FieldThree = string.Empty;

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            PickerDialogType = typeof(ContentLookupFieldEntityEditor);
            string customProp = Context.Request.QueryString["CustomProperty"];
            if (!string.IsNullOrEmpty(customProp))
            {
                customProp = Microsoft.SharePoint.Utilities.SPHttpUtility.UrlKeyValueDecode(customProp);
                string[] sourceData = customProp.Split(';');
                if (sourceData.Length >4)
                {
                    _WebURL = sourceData[0];
                    _ListName = sourceData[1];
                    _FieldOne = sourceData[2];
                    _FieldTwo = sourceData[3];
                    if (sourceData.Length > 4) _FieldThree = sourceData[4];
                }
            }
        }


        public override PickerEntity ValidateEntity(PickerEntity needsValidation)
        {

            using (SPSite topSite = new SPSite(_WebURL))
            {
                using (SPWeb topWeb = topSite.OpenWeb())
                {
                    SPList searchList = topWeb.Lists[_ListName];
                    SPListItemCollection searchItems = null;
                    SPQuery searchQuery = new SPQuery();
                    searchQuery.ViewFields = string.Format("<FieldRef Name=\"{0}\" /><FieldRef Name=\"{1}\" />", _FieldOne, _FieldTwo);
                    searchQuery.Query = string.Format("<Where><Eq><FieldRef Name='{0}' Nullable=\"TRUE\"/><Value Type=\"Text\">{1}</Value></Eq></Where>", _FieldOne, needsValidation.Key);
                    searchItems = searchList.GetItems(searchQuery);
                    if (null != searchItems)
                    {
                        if (searchItems.Count > 0)
                        {
                            object valueTest = searchItems[0][_FieldTwo];
                            if (null != valueTest)
                            {
                                needsValidation.Key = searchItems[0][_FieldOne].ToString();
                                needsValidation.DisplayText = searchItems[0][_FieldTwo].ToString();
                                needsValidation.IsResolved = true;
                            }
                        }
                    }
                }
            }
            return needsValidation;
        }

    }
    #endregion

    #region PickerDialog
    [CLSCompliant(false)]
    [Guid("169369AE-B15B-49b1-9B01-11F8C1841A99")]
    public class ContentLookupFieldPickerDialog : Microsoft.SharePoint.WebControls.PickerDialog
    {
        public ContentLookupFieldPickerDialog()
            : base(new ContentLookupFieldQueryControl(), new TableResultControl(), new ContentLookupFieldEntityEditor())
        {
            //Our display columns are only the first and second field,
            //all other fields are searchable but we only display the first
            //two in the search box
            base.Description = "Find search for linked data ";
            string customProp = Context.Request.QueryString["CustomProperty"];
            if (!string.IsNullOrEmpty(customProp))
            {
                customProp = Microsoft.SharePoint.Utilities.SPHttpUtility.UrlKeyValueDecode(customProp);
                string[] sourceData = customProp.Split(';');
                if (sourceData.Length >= 4)
                {
                    ArrayList columnDisplayNames = ((TableResultControl)base.ResultControl).ColumnDisplayNames;
                    columnDisplayNames.Clear();
                    if (!string.IsNullOrEmpty(sourceData[2])) columnDisplayNames.Add(sourceData[2]);
                    if (!string.IsNullOrEmpty(sourceData[3])) columnDisplayNames.Add(sourceData[3]);

                    ArrayList columnNames = ((TableResultControl)base.ResultControl).ColumnNames;
                    columnNames.Clear();
                    if (!string.IsNullOrEmpty(sourceData[2])) columnNames.Add(sourceData[2]);
                    if (!string.IsNullOrEmpty(sourceData[3])) columnNames.Add(sourceData[3]);

                    ArrayList columnWidths = ((TableResultControl)base.ResultControl).ColumnWidths;
                    columnWidths.Clear();
                    columnWidths.Add("30%");
                    if (!string.IsNullOrEmpty(sourceData[4])) columnWidths.Add("70%");
                }
            }
            ((ContentLookupFieldQueryControl)this.QueryControl).ParentDialog = this;
        }
    }
    #endregion

    #region SimpleQueryControl
    [CLSCompliant(false)]
    [Guid("22EE2F6D-2020-490a-B0D2-37A680ED6098")]
    public class ContentLookupFieldQueryControl : Microsoft.SharePoint.WebControls.SimpleQueryControl
    {
        const string SEARCH_ALL = "Search All";
        //this class executes the query against the configured list
        //and returns any matching values in the query selector dataset
        private string _WebURL = string.Empty;
        private string _ListName = string.Empty;
        private string _FieldOne = string.Empty;
        private string _FieldTwo = string.Empty;
        private string _FieldThree = string.Empty;
        private string _FieldOneInternalName = string.Empty;
        private string _FieldTwoInternalName = string.Empty;
        private string _FieldThreeInternalName = string.Empty;

        private SPList _SearchList = null;
        internal ContentLookupFieldPickerDialog ParentDialog = null;

        public ContentLookupFieldQueryControl()
        {
            
            this.Load += new EventHandler(SOTFCurriculumLinksQueryControl_Load);
            string customProp = Context.Request.QueryString["CustomProperty"];
            if (!string.IsNullOrEmpty(customProp))
            {
                customProp = Microsoft.SharePoint.Utilities.SPHttpUtility.UrlKeyValueDecode(customProp);
                string[] sourceData = customProp.Split(';');
                if (sourceData.Length >= 4)
                {
                    _WebURL = sourceData[0];
                    _ListName = sourceData[1];
                    _FieldOne = sourceData[2];
                    _FieldTwo = sourceData[3];
                    if (sourceData.Length > 4) _FieldThree = sourceData[4];
                    using (SPSite topSite = new SPSite(_WebURL))
                    {
                        using (SPWeb topWeb = topSite.OpenWeb())
                        {
                            _SearchList = topWeb.Lists[_ListName];
                            _FieldOneInternalName = GetInternalName(_FieldOne);
                            _FieldTwoInternalName = GetInternalName(_FieldTwo);
                            _FieldThreeInternalName = GetInternalName(_FieldThree);
                        }
                    }
                }
            }
        }

        private string GetInternalName(string fieldName)
        {
            string returnValue = string.Empty;
            if (_SearchList.Fields.ContainsField(fieldName))
            {
                SPField fieldOne = _SearchList.Fields.GetField(fieldName);
                returnValue = fieldOne.InternalName;
            }
            return returnValue;
        }

        void SOTFCurriculumLinksQueryControl_Load(object sender, EventArgs e)
        {
            if (!Page.IsPostBack)
            {
                EnsureChildControls();
                mColumnList.Items.Add(SEARCH_ALL);
                if (!string.IsNullOrEmpty(_FieldOne)) mColumnList.Items.Add(_FieldOne);
                if (!string.IsNullOrEmpty(_FieldTwo)) mColumnList.Items.Add(_FieldTwo);
                if (!string.IsNullOrEmpty(_FieldThree)) mColumnList.Items.Add(_FieldThree);
            }
        }


        protected override int IssueQuery(string search, string groupName, int pageIndex, int pageSize)
        {
            DataTable searchResults = SearchResults(groupName, search);
            PickerDialog.Results = searchResults;
            PickerDialog.ResultControl.PageSize = searchResults.Rows.Count;
            return searchResults.Rows.Count;
        }

        private string CAMLOneFieldQuery(string queryString)
        {
           string fieldName = _FieldOneInternalName;
           if (string.IsNullOrEmpty(fieldName)) fieldName = _FieldTwoInternalName;
           if (string.IsNullOrEmpty(fieldName)) fieldName = _FieldThreeInternalName;
           return string.Format("<Contains><FieldRef Name='{0}' Nullable=\"TRUE\"/><Value Type=\"Text\">{1}</Value></Contains>", fieldName, queryString);
        }
        
        private string CAMLTwoFieldQuery(string queryString)
        {
            System.Text.StringBuilder returnValue = new System.Text.StringBuilder();
            string fieldNameOne = _FieldOneInternalName;
            string fieldNameTwo = _FieldTwoInternalName;
            if (string.IsNullOrEmpty(fieldNameOne)) fieldNameOne = _FieldThreeInternalName;
            if (string.IsNullOrEmpty(fieldNameTwo)) fieldNameTwo = _FieldThreeInternalName;
            returnValue.AppendFormat("<Or><Contains><FieldRef Name='{0}' Nullable=\"TRUE\"/><Value Type=\"Text\">{1}</Value></Contains>", fieldNameOne, queryString);
            returnValue.AppendFormat("<Contains><FieldRef Name='{0}' Nullable=\"TRUE\"/><Value Type=\"Text\">{1}</Value></Contains></Or>", fieldNameTwo, queryString);
            return returnValue.ToString();
        }

        private string CAMLThreeFieldQuery(string queryString)
        {
            System.Text.StringBuilder returnValue = new System.Text.StringBuilder();
            returnValue.AppendFormat("<Or><Or><Contains><FieldRef Name='{0}' Nullable=\"TRUE\"/><Value Type=\"Text\">{1}</Value></Contains>", _FieldOneInternalName, queryString);
            returnValue.AppendFormat("<Contains><FieldRef Name='{0}' Nullable=\"TRUE\"/><Value Type=\"Text\">{1}</Value></Contains></Or>", _FieldTwoInternalName, queryString);
            returnValue.AppendFormat("<Contains><FieldRef Name='{0}' Nullable=\"TRUE\"/><Value Type=\"Text\">{1}</Value></Contains></Or>", _FieldThreeInternalName, queryString);
            return returnValue.ToString();
        }

        private string CAMLQuery(string fieldName, string queryString)
        {
            System.Text.StringBuilder returnValue = new System.Text.StringBuilder();
            if (!string.IsNullOrEmpty(_FieldOneInternalName)) returnValue.AppendFormat("<OrderBy><FieldRef Name=\"{0}\" /></OrderBy>", _FieldOneInternalName);
            if (SEARCH_ALL == fieldName)
            {
                int validFieldCount = 0;
                if (!string.IsNullOrEmpty(_FieldOneInternalName)) validFieldCount++;
                if (!string.IsNullOrEmpty(_FieldTwoInternalName)) validFieldCount++;
                if (!string.IsNullOrEmpty(_FieldThreeInternalName)) validFieldCount++;
                returnValue.Append("<Where>");
                //this is kind of simplistic but it works, if we had an arbritray number of fields
                //we would need something more elegant
                switch (validFieldCount)
                {
                    case 1:
                        returnValue.Append(CAMLOneFieldQuery(queryString));
                        break;
                    case 2:
                        returnValue.Append(CAMLTwoFieldQuery(queryString));
                        break;
                    case 3:
                        returnValue.Append(CAMLThreeFieldQuery(queryString));
                        break;
                }
                returnValue.Append("</Where>");
            }
            else
            {
                if (_FieldOne == fieldName)
                {
                    fieldName = _FieldOneInternalName;
                }
                else
                {
                    if (_FieldTwo == fieldName)
                    {
                        fieldName = _FieldTwoInternalName;
                    }
                    else
                    {
                        if (_FieldThree == fieldName) fieldName = _FieldThreeInternalName;
                    }
                }
                returnValue.AppendFormat("<Where><Contains><FieldRef Name='{0}' Nullable=\"TRUE\"/><Value Type=\"Text\">{1}</Value></Contains></Where>", fieldName, queryString);
            }
            return returnValue.ToString();

        }

        private string CAMLViewFields()
        {
            System.Text.StringBuilder returnValue = new System.Text.StringBuilder();
            if (!string.IsNullOrEmpty(_FieldOneInternalName)) returnValue.AppendFormat("<FieldRef Name=\"{0}\" />", _FieldOneInternalName);
            if (!string.IsNullOrEmpty(_FieldTwoInternalName)) returnValue.AppendFormat("<FieldRef Name=\"{0}\" />", _FieldTwoInternalName);
            if (!string.IsNullOrEmpty(_FieldThreeInternalName)) returnValue.AppendFormat("<FieldRef Name=\"{0}\" />", _FieldThreeInternalName);
            return returnValue.ToString();
        }

        private void AddRowValue(DataRow dRow, SPListItem listItem, string fieldName)
        {
            if (!string.IsNullOrEmpty(fieldName))
            {
                object fieldValue = listItem[fieldName];
                if (null != fieldValue)
                {
                    dRow[fieldName] = fieldValue.ToString();
                }
            }
        }

        private DataTable SearchResults(string searchField, string queryText)
        {
            DataTable returnValue = new DataTable();
            if (null == queryText)
            {
                queryText = string.Empty;
            }
            else
            {
                queryText = queryText.Trim();
            }
            if (!string.IsNullOrEmpty(_FieldOneInternalName)) returnValue.Columns.Add(_FieldOneInternalName);
            if (!string.IsNullOrEmpty(_FieldTwoInternalName)) returnValue.Columns.Add(_FieldTwoInternalName);
            // We only display columns one and two, column one is the "key" for data entry
            try
            {
                SPListItemCollection searchItems = null;
                if (string.IsNullOrEmpty(queryText))
                {
                    searchItems = _SearchList.Items;
                }
                else
                {
                    SPQuery searchQuery = new SPQuery();
                    searchQuery.Query = CAMLQuery(searchField, queryText);
                    searchQuery.ViewFields = CAMLViewFields();
                    searchItems = _SearchList.GetItems(searchQuery);
                }
                foreach (SPListItem foundItem in searchItems)
                {
                    DataRow newRow = returnValue.NewRow();
                    AddRowValue(newRow, foundItem, _FieldOneInternalName);
                    AddRowValue(newRow, foundItem, _FieldTwoInternalName);
                    returnValue.Rows.Add(newRow);
                }
 
            }
            catch (Exception searchError)
            {
                if (null != ParentDialog)
                {
                    ParentDialog.ErrorMessage = searchError.Message;
                }
            }
            return returnValue;
        }

        public override PickerEntity GetEntity(DataRow dr)
        {
            PickerEntity entity = new PickerEntity();
            entity.DisplayText = string.Empty + dr[_FieldOneInternalName];
            entity.Key = string.Empty + dr[_FieldOneInternalName];
            entity.Description = string.Empty + dr[_FieldTwoInternalName];
            entity.IsResolved = true;
            return entity;
        }

    }
    #endregion
}

